#include <iostream>
#include <sstream>
#include <string>

#define _OSS_CLIENT_H
#include <modules/oss_client.h>
#undef _OSS_CLIENT_H

using namespace osscpp;

#include "ossstor.h"
#include "config.h"

using std::string;
using std::stringstream;

OSSStorage::OSSStorage() : connected(false) {

}

int OSSStorage::connect() {
	if (!connected) {
		connected = true;
		return 0;
	}
	return -1;
}

void OSSStorage::disconnect() {
	if (connected) {
		connected = false;
	}
}

int OSSStorage::get(const char* pathname,char* buffer,size_t size) {
	string oid = Config::Get("oss-id"),
		okey = Config::Get("oss-key"),
		endpoint = Config::Get("oss-endpoint"),
		bucket = Config::Get("oss-bucket");

	OSS_ERROR_CODE retcode;

	Client client(oid, okey, endpoint);

	void *bufferint = NULL;
	unsigned int bufferint_len = 0;
	int pathlen = strlen(pathname);

	char *pathint = (char*)malloc((pathlen+1)*sizeof(char));
	strcpy(pathint, pathname);
	if (pathint[0] == '/') pathint[0] = '#';

	GetObjectRequest request(bucket, pathint);

	ObjectMetadata metadata = client.GetObject(request, &bufferint, bufferint_len, retcode);


	size_t realsize = size < bufferint_len ? size : bufferint_len;

	memcpy(buffer, bufferint, realsize);

	free(bufferint);
	free(pathint);

	if(retcode != 0) {
		return -1;
	}
	return realsize;
}

int OSSStorage::put(const char* pathname,const char* buffer,size_t size) {
	string oid = Config::Get("oss-id"),
		okey = Config::Get("oss-key"),
		endpoint = Config::Get("oss-endpoint"),
		bucket = Config::Get("oss-bucket");

	OSS_ERROR_CODE retcode;

	Client client(oid, okey, endpoint);

	int pathlen = strlen(pathname);

	char *pathint = (char*)malloc((pathlen+1)*sizeof(char));
	strcpy(pathint, pathname);
	if (pathint[0] == '/') pathint[0] = '#';

	stringstream strm;
	strm << size;
	/* 初始化元信息，并设置相关属性 */
	ObjectMetadata metadata;
	metadata.set_content_length(strm.str()); /** 该参数必须设置 */
	metadata.set_content_type("application/octet-stream");
	metadata.set_cache_control("no-cache");
	metadata.set_content_encoding("utf-8");
	metadata.set_content_disposition("attachment;");

	char *bufferint = (char*)malloc((size+1)*sizeof(char));
	memset(bufferint, 0, size+1);
	memcpy(bufferint, buffer, size*sizeof(char));
	bufferint[size] = '\0';

	

	/* 将内存中的内容上传至云服务器中 */
	PutObjectResult result = client.PutObjectFromBuffer(bucket, pathint, bufferint, size, metadata, retcode);

	free(pathint);
	free(bufferint);
	if(retcode == 0) {
		return 0;
	} else {
		return -1;
	}
}

int OSSStorage::del(const char* pathname) {
	string oid = Config::Get("oss-id"),
		okey = Config::Get("oss-key"),
		endpoint = Config::Get("oss-endpoint"),
		bucket = Config::Get("oss-bucket");

	OSS_ERROR_CODE retcode;

	Client client(oid, okey, endpoint);

	int pathlen = strlen(pathname);
	char *pathint = (char*)malloc((pathlen+1)*sizeof(char));
	strcpy(pathint, pathname);

	if (pathint[0] == '/') pathint[0] = '#';

	client.DeleteObject(bucket, pathint, retcode);
	
	free(pathint);

	if(retcode == 0) {
		return 0;
	} else {
		return -1;
	}
}

int OSSStorage::mkdir(const char* path,const char* name) {
	string str;
	str = str + path + name + "/";
	char buffer[4] = "dir";

	return put(str.c_str(), buffer, 3);
}

int OSSStorage::rmdir(const char* path,const char* name) {
	string str;
	str = str + path + name + "/";

	return del(str.c_str());
}

struct NetFile* OSSStorage::lsdir(const char* path,OUT int* size /* numbner of struct NetFile */) {
	string oid = Config::Get("oss-id"),
		okey = Config::Get("oss-key"),
		endpoint = Config::Get("oss-endpoint"),
		bucket = Config::Get("oss-bucket");

	OSS_ERROR_CODE retcode;
	Client client(oid, okey, endpoint);
	ObjectListing object_listing = client.ListObjects(bucket, path, retcode);

	if(retcode == 0) {
		size_t count = object_listing.summaries().size();
		NetFile *files = (NetFile*)malloc(sizeof(NetFile) * count);
		for(int i = 0; i < count; i++) {
			string help = (object_listing.summaries())[i].key();
			strcpy(files[0].fileName, help.c_str());
			files[0].size = (object_listing.summaries())[i].size();
			files[0].folder = help[help.length()-1] == '/'? 1:0;
		}
		*size = count;
		return files;
	} else {
		*size = 0;
		return NULL;
	}
	*size = 0;
	return NULL;
}

int OSSStorage::move(const char* oldPath,const char* newPath) {
	string oid = Config::Get("oss-id"),
		okey = Config::Get("oss-key"),
		endpoint = Config::Get("oss-endpoint"),
		bucket = Config::Get("oss-bucket");

	OSS_ERROR_CODE retcode;

	Client client(oid, okey, endpoint);

	int pathlen1 = strlen(oldPath),
		pathlen2 = strlen(newPath);

	char *pathint1 = (char*)malloc((pathlen1+1)*sizeof(char)),
		*pathint2 = (char*)malloc((pathlen2+1)*sizeof(char));

	strcpy(pathint1, oldPath);
	strcpy(pathint2, newPath);

	if (pathint1[0] == '/') pathint1[0] = '#';
	if (pathint2[0] == '/') pathint2[0] = '#';

	CopyObjectRequest request(bucket, pathint1,
			bucket, pathint2);
	CopyObjectResult result;
	result = client.CopyObject(request, retcode);

	free(pathint1);
	free(pathint2);

	if(retcode == 0) {
		return del(oldPath);
	} else {
		return -1;
	}

	return 0;
}

int OSSStorage::freespace() {
	return -1;
}

int OSSStorage::init() {
	return 0;
}

int OSSStorage::destroy() {
	return 0;
}
